﻿using System.Collections.Concurrent;
using System.Text;
using System.Text.RegularExpressions;
using TrackSystem.Entities.Extensions;
using TrackSystem.IO.Data;
using TrackSystem.IO.Utils;

namespace TrackSystem.IO.Formula
{
    /// <summary>
    /// 表达式计算类
    /// </summary>
    public class ClacuationFormula
    {
        /// <summary>
        /// 静态初始值
        /// </summary>
        public static Random rand = new Random((int)DateTime.Now.Ticks);
        
        /// <summary>
        /// 表达式预处理
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static FormulaResult PreTreat(string exp)
        {
            if (string.IsNullOrEmpty(exp))
            {
                return FormulaResult.Fail("表达式为空");
            }

            exp = exp.Replace(" ", "").Replace("\t", "").Replace("\r", "").Replace("\n", "");
            if (string.IsNullOrEmpty(exp))
            {
                return FormulaResult.Fail("表达式为空");
            }
            
            if (!IsBrackMatch(exp))
            {
                return FormulaResult.Fail("括号不匹配");
            }
            exp += "@";

            // 如果所有的不区分大小写，去掉下面的注释
            //exp = exp.ToLower();
            //exp += "@";

            return FormulaResult.Ok(exp, exp);
        }

        /// <summary>
        /// 判断表示左右括号是否匹配
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static bool IsBrackMatch(string exp)
        {
            int cur = 0;

            foreach (char ch in exp)
            {
                if (ch == '(')
                    cur++;

                if (ch == ')')
                    cur--;

                if (cur < 0)
                    return false;
            }

            return cur == 0;
        }

        /// <summary>
        /// 元素切割
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static List<string> Segment(string exp)
        {
            List<char> SPLIT_SYMBOL = new List<char> {'+', '-', '*', '/', '?', ':','<', '>', '=', '!', '(', ')', '|', '&', '@', '^', '%', ','};

            List<string> segments = new List<string>();

            StringBuilder element = new StringBuilder();

            int current = 0;
            bool bEleStart = true;     //变量或常量的开始

            while (current < exp.Length)
            {
                if (SPLIT_SYMBOL.Contains(exp[current]))
                {
                    if (element.Length > 0)
                    {
                        segments.Add(element.ToString());
                        element.Clear();
                    }

                    segments.Add(exp[current].ToString());
                    switch (exp[current])
                    {
                        case '<':
                            if (exp[current + 1] == '>' || exp[current + 1] == '=')
                            {
                                segments[^1] += exp[current + 1];
                                current++;
                            }
                            break;

                        case '>':
                        case '!':
                            if (exp[current + 1] == '=')
                            {
                                segments[^1] += exp[current + 1];
                                current++;
                            }
                            break;

                        case '|':
                            if (exp[current + 1] == '|')
                            {
                                segments[^1] += exp[current + 1];
                                current++;
                            }
                            break;

                        case '&':
                            if (exp[current + 1] == '&')
                            {
                                segments[^1] += exp[current + 1];
                                current++;
                            }
                            break;

                        case '=':
                            if (exp[current + 1] == '=')
                            {
                                segments[^1] += exp[current + 1];
                                current++;
                            }
                            break;
                    }
                    bEleStart = true;
                }
                else
                {
                    // 如果操作数开始
                    if (bEleStart)
                    {
                        bEleStart = false;

                        element.Clear();
                        element.Append(exp[current]);
                    }
                    else
                    {
                        element.Append(exp[current]);
                    }
                }

                current++;
            }

            if (element.Length > 0)
            {
                segments.Add(element.ToString());
            }

            return segments;
        }

        /// <summary>
        /// 中缀表达式
        /// </summary>
        /// <param name="segments"></param>
        /// <param name="syntax"></param>
        /// <param name="varList"></param>
        /// <returns></returns>
        public static FormulaResult Parse(List<string> segments, Stack<ExprItem> syntax, Dictionary<string, DataTypeEnum> varList = null)
        {
            Stack<object> operands = new Stack<object>();           // 操作数堆栈
            Stack<Operator> operators = new Stack<Operator>();      // 运算符堆栈

            bool pre_opt = true;        // 前一个是运算符号
            int quest_level = 0;        // 当前question层数
            for (int i = 0; i < segments.Count; i++)
            {
                string ele = segments[i];
                string ele_lo = ele.ToLower();

                if (ele_lo == ",")
                    continue;

                if (KeywordsHelper.Instance.sKeys.TryGetValue(ele, out var opDef))
                {
                    // 创建新的运算符
                    Operator opt = new Operator(opDef, !pre_opt);

                    // 如果特殊计算方法，可增加到FormulaTools字典中
                    FormulaTools.Instance.TryAdd(opt);

                    if (opt.Type == OperatorType.COLON)
                    {
                        quest_level--;
                        if (quest_level < 0)
                        {
                            throw new Exception("Colon don't match");
                        }
                    }

                    // 正号和加号的判断
                    if (opt.Type == OperatorType.ADD && pre_opt)
                    {
                        opt.Type = OperatorType.PS;
                        opt.opChar = "!+";
                        opt.OpNum = 1;  // 正号只有一个操作数
                    }

                    // 负号和减号的判断
                    if (opt.Type == OperatorType.SUB && pre_opt)
                    {
                        opt.Type = OperatorType.NS;
                        opt.opChar = "!-";
                        opt.OpNum = 1;  // 正号只有一个操作数
                    }

                    pre_opt = true;

                    // 若当前是结束运算符，则停止循环
                    if (opt.Type == OperatorType.END)
                        break;

                    // 若当前是左括号, 这直接存入堆栈
                    if (opt.Type == OperatorType.LB)
                    {
                        if (KeywordsHelper.Instance.sKeys.TryGetValue("(", out var opLb))
                            operators.Push(new Operator(opLb, true));  //OperatorType.LB));
                        continue;
                    }

                    // 若当前为右括号，则依次弹出运算符堆栈中的运算符存入到操作数堆栈，直到右括号为止，此时抛弃左括号
                    if (opt.Type == OperatorType.RB)
                    {
                        while (operators.Count > 0)
                        {
                            if (operators.Peek().Type != OperatorType.LB)
                            {
                                operands.Push(operators.Pop());
                            }
                            else
                            {
                                operators.Pop();
                                break;
                            }
                        }
                        pre_opt = false;
                        continue;
                    }

                    // 若当前为疑问号，则将优先级小于的运算符出栈，并将本身存入堆栈
                    if (opt.Type == OperatorType.QUESTION)
                    {
                        quest_level++;
                        while (operators.Count > 0)
                        {
                            if (!opt.CompareTo(operators.Peek().Type) && operators.Peek().Type != OperatorType.LB)
                            {
                                operands.Push(operators.Pop());
                            }
                            else
                            {
                                break;
                            }
                        }
                        operands.Push(opt);
                        continue;
                    }

                    //若运算符堆栈为空 或者运算符堆栈顶为左括号，则直接将当前运算符存入运算符堆栈
                    if (operators.Count == 0 || operators.Peek().Type == OperatorType.LB)
                    {
                        operators.Push(opt);
                        continue;
                    }

                    // 若运算符堆栈优先级高于栈顶
                    if (opt.CompareTo(operators.Peek().Type))
                    {
                        operators.Push(opt);
                    }
                    else
                    {
                        //若优先级相等或较低，则输出栈顶运算符到操作数堆栈，直至
                        while (operators.Count > 0)
                        {
                            if (!opt.CompareTo(operators.Peek().Type) && operators.Peek().Type != OperatorType.LB)
                            {
                                operands.Push(operators.Pop());
                                if (operators.Count == 0)
                                {
                                    operators.Push(opt);
                                    break;
                                }
                            }
                            else
                            {
                                operators.Push(opt);
                                break;
                            }
                        }
                    }
                }
                else
                {
                    operands.Push(ele);
                    pre_opt = false;
                }
            }

            // 剩余的操作符，一并进入语法单元堆栈
            while (operators.Count > 0)
            {
                operands.Push(operators.Pop());
            }

            // 构建语法单元，将运算符、常量、变量进行区分，并且确定变量是否存在
            string errorMsg = string.Empty;
            while (operands.Count > 0)
            {
                var item = operands.Pop();
                ExprItem exprItem = new ExprItem();

                //  item 是字符串
                if (item is string)
                {
                    string? regName = item as string;
                    if (regName == null)
                        return FormulaResult.Fail($"表达式错误，变量[{item.ToString()}]不存在");

                    try
                    {
                        // 预定义常量PI ----
                        if (regName == "pi")
                        {
                            exprItem.Operand = new OperandDef(3.1415926535);
                            exprItem.synType = SynType.Nm;
                        }
                        else if (varList != null && varList.TryGetValue(regName, out var regType))
                        {
                            exprItem.varName = regName;
                            exprItem.synType = SynType.Vr;
                            exprItem.Operand = new OperandDef(regType);
                        }
                        else if (OperandDef.TryParse(regName, out OperandDef operand))
                        {
                            exprItem.Operand = operand;
                            exprItem.synType = SynType.Nm;
                        }
                        else
                        {
                            errorMsg += regName + ",";
                        }
                    }
                    catch (Exception)
                    {
                        errorMsg += regName + ", ";
                    }

                    syntax.Push(exprItem);
                    continue;
                }

                // item 是操作符  ----------------------
                Operator? op = item as Operator;
                if (op is null)
                    return FormulaResult.Fail($"表达式错误，变量[{item.ToString()}]不存在");
                exprItem.operatorType = op.Type;
                exprItem.OpId = op.Id;
                exprItem.OpNum = op.OpNum;
                exprItem.OpName = op.opChar;
                exprItem.synType = SynType.Op;

                syntax.Push(exprItem);
            }

            if (string.IsNullOrEmpty(errorMsg)) return FormulaResult.Ok("表达式正确");

            // 如果有错误，返回错误信息
            return FormulaResult.Fail($"表达式错误，变量[{errorMsg}]不存在");
        }

        /// <summary>
        /// （1）初始化一个空堆栈。
        /// （2）从左到右读入后缀表达式。
        /// （3）如果字符是一个操作数，把它压入堆栈。
        /// （4）如果字符是个运算符，根据运算符的需求弹出相应个数的操作数，执行恰当操作，然后把结果压入堆栈。
        /// （5）到后缀表达式末尾，从堆栈中弹出结果。
        /// </summary>
        /// <param name="syntax">后缀表达式堆栈</param>
        /// <param name="bTest">是否用于测试表达式，可选用1代入进行</param>
        /// <returns></returns>
        public static OperandDef Evaluate(Stack<ExprItem> syntax, bool bTest = false)
        {
            if (syntax.Count == 0)
            {
                return new OperandDef();
            }

            Stack<OperandDef> opds = new();
            var num = new OperandDef[4];

            foreach (ExprItem item in syntax)
            {
                // ----CONDITION 1   运算数 -----------------
                // 取出变量
                if (item.synType != SynType.Op)   
                {
                    // ---- 常量 ------------------
                    if (item.synType == SynType.Nm)
                    { 
                        //opds.Push(item.normalVal);
                        opds.Push(item.Operand?.Clone());
                    }
                    else  // ---- 变量 ------------------
                    {
                        if (bTest)
                        {
                            opds.Push((OperandDef)item.Operand);
                        }
                        else
                        {
                            if (RegFactory.Instance.Regs.TryGetValue(item.varName, out var reg))
                            {
                                opds.Push(reg);
                            }
                            else
                                throw new Exception($"表达式计算: 变量名 {item.varName} 不存在!");
                        }
                    }
                    continue;
                }

                // ----------CONDITION 2 运算符 ------------------------------
                // 根据不同的条件从堆栈中取出12操作数
                if (item.OpNum > 0)
                {
                    if (item.OpNum > opds.Count)
                    {
                        throw new Exception($"操作 {item.OpName} 需要 {item.OpNum} 个操作数, 但是仅提供 {opds.Count} 个");
                    }
                    
                    // ------ 取操作数 -------------
                    for (int i = 0; i < item.OpNum; i++)
                    {
                        num[i] = opds.Pop();
                    }

                    if (item.OpName == "filter")
                    {
                        item.OpName = "filter";
                    }

                    // 操作数运算
                    if (KeywordsHelper.Instance.sKeys.TryGetValue(item.OpName, out var opKey))
                    {
                        // 使用预定义的函数进行计算
                        opds.Push(opKey.HandleFunc(num, item.OpId));
                    }
                }
            }

            // -------------------------------------------------
            if (opds.Count != 1)
            {
                throw new Exception("Expression error");
            }
            return opds.Pop();
        }

        /// <summary>
        /// 根据表达式进行计算
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static FormulaResult Evaluate(string exp)
        {
            try
            {
                var result = PreTreat(exp);
                if (!result.Success)
                {
                    return FormulaResult.Fail(result.Message ??= "预处理发生错误");
                }
                List<string> lstResult = Segment(result.Message ??= "@");

                Stack<ExprItem> exprStack = new Stack<ExprItem>();
                var rest = Parse(lstResult, exprStack);
                if (!rest.Success)
                    return FormulaResult.Fail(rest.Message ??="表达式错误");

                var Value = Evaluate(exprStack);
                return FormulaResult.Ok(Value);
            }
            catch (Exception ex)
            {
                return FormulaResult.Fail(ex.Message);
            }
        }

        /// <summary>
        /// 用来测试输入的表达式是否正确的函数
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="varList"></param>
        /// <returns></returns>
        public static FormulaResult TestFormula(string expression, Dictionary<string, DataTypeEnum> varList)
        {
            try
            {
                // 预处理表达式
                var result = PreTreat(expression);
                if (!result.Success)
                {
                    return FormulaResult.Fail(result.Message ??= "预处理发生错误");
                }
                List<string> lstResult = Segment(result.Message ??= "@");


                Stack<ExprItem> exprStack = new Stack<ExprItem>();

                // 解析表达式
                var rest = Parse(lstResult, exprStack, varList);
                if (!rest.Success)
                    return FormulaResult.Fail(rest.Message ??= "表达式错误");

                // 计算表达式
                var value = Evaluate(exprStack, true);
                return FormulaResult.Ok(value, value.ToString());
            }
            catch (Exception ex)
            {
                return FormulaResult.Fail(ex.Message);
            }
        }

        /// <summary>
        /// 是否合法
        /// </summary>
        /// <param name="name">名称</param>
        /// <returns></returns>
        public static bool IsVaild(string name)
        {
            string pattern = "^[a-zA-Z_][a-zA-Z0-9_]*$";
            return Regex.IsMatch(name, pattern);
        }

    }
}
